// Tasks data storage
let tasks = [];

// Date range filter
let activeRange = 'week';

// DOM loaded event
document.addEventListener('DOMContentLoaded', function () {
  console.log("Reports page loaded, initializing...");

  // Load tasks data
  loadTasksFromStorage();

  // Set up date range filter buttons
  initDateRangeFilters();

  // Generate reports based on default filter (this week)
  //generateReports(); // 已在 loadTasksFromStorage 里调用

  // 监听 chrome.storage.local 变化，实现数据实时同步
  if (window.chrome && chrome.storage && chrome.storage.onChanged) {
    chrome.storage.onChanged.addListener(function(changes, areaName) {
      if (areaName === 'local' && changes.taskTrackerTasks) {
        console.log('Detected taskTrackerTasks change, reloading...');
        loadTasksFromStorage();
      }
    });
  }
});

// Load tasks from chrome.storage.local（优先chrome.storage.local，兼容localStorage）
function loadTasksFromStorage() {
  console.log("Loading tasks from storage...");
  if (window.chrome && chrome.storage && chrome.storage.local) {
    chrome.storage.local.get(['taskTrackerTasks'], function(result) {
      const storedTasks = result.taskTrackerTasks;
      if (storedTasks) {
        try {
          tasks = storedTasks;
          console.log(`Successfully loaded ${tasks.length} tasks`);
          // Ensure all tasks have creation date
          tasks.forEach(task => {
            if (!task.createdAt) {
              task.createdAt = new Date().toISOString();
            }
          });
          // Sort tasks by creation time (latest first)
          tasks.sort((a, b) => {
            const dateA = new Date(a.createdAt || 0);
            const dateB = new Date(b.createdAt || 0);
            return dateB - dateA;
          });
        } catch (error) {
          console.error("Error parsing task data:", error);
          showNotification("Error loading task data", "error");
          tasks = [];
        }
      } else {
        console.log("No tasks found in storage");
        tasks = [];
      }
      // 重新生成报表
      generateReports();
    });
  } else {
    // chrome.storage.local 不可用，直接提示错误
    showNotification("chrome.storage.local is not available!", "error");
    tasks = [];
    generateReports();
  }
}

// Initialize date range filter buttons
function initDateRangeFilters() {
  const dateButtons = document.querySelectorAll('.date-range-btn');

  dateButtons.forEach(button => {
    button.addEventListener('click', function () {
      // Skip if already active
      if (this.classList.contains('active')) return;

      // Remove active class from all buttons
      dateButtons.forEach(btn => btn.classList.remove('active'));

      // Add active class to clicked button
      this.classList.add('active');

      // Update active range
      activeRange = this.getAttribute('data-range');

      // Regenerate reports with new date range
      generateReports();
    });
  });
}

// Get date range based on selected filter
function getDateRange() {
  const now = new Date();
  let startDate = new Date();

  switch (activeRange) {
    case 'week':
      // Start from previous Monday
      const dayOfWeek = now.getDay(); // 0 is Sunday, 1-6 is Monday-Saturday
      const diff = dayOfWeek === 0 ? 6 : dayOfWeek - 1; // Adjust for Sunday
      startDate.setDate(now.getDate() - diff);
      break;

    case 'month':
      // Start from first day of current month
      startDate = new Date(now.getFullYear(), now.getMonth(), 1);
      break;

    case 'quarter':
      // Start from 3 months ago
      startDate = new Date(now.getFullYear(), now.getMonth() - 3, now.getDate());
      break;

    case 'year':
      // Start from January 1st of current year
      startDate = new Date(now.getFullYear(), 0, 1);
      break;

    case 'all':
      // All time (use a far past date)
      startDate = new Date(2000, 0, 1);
      break;
  }

  // Set time to beginning of day for start date
  startDate.setHours(0, 0, 0, 0);

  // Set end date to end of current day
  const endDate = new Date();
  endDate.setHours(23, 59, 59, 999);

  return { startDate, endDate };
}

// Filter tasks by date range
function filterTasksByDateRange() {
  const { startDate, endDate } = getDateRange();
  // debugger
  const rs = tasks.filter(task => {
    // 对已完成任务使用completedAt时间，其他任务使用createdAt时间
    if(task.title == '信安对接开发'){
      // debugger
    }      

    const isCompleted = task.status && task.status.toLowerCase() === 'completed';
    const taskDate = isCompleted && task.completedAt
      ? new Date(task.completedAt)
      : new Date(task.createdAt);

    return taskDate >= startDate && taskDate <= endDate;
  });
  console.log(rs);
  return rs;
}

// Generate all reports
function generateReports() {
  console.log(`Generating reports for range: ${activeRange}`);

  // Show loading state
  document.querySelectorAll('.summary-value').forEach(el => {
    el.textContent = '...';
  });

  // Get filtered tasks
  const filteredTasks = filterTasksByDateRange();
  console.log(`Filtered tasks: ${filteredTasks.length}`);

  // Generate summary statistics
  generateSummaryStats(filteredTasks);

  // Generate status distribution
  generateStatusDistribution(filteredTasks);

  // Generate tags analysis
  generateTagsAnalysis(filteredTasks);

  // Generate charts
  generateCompletionTrendChart(filteredTasks);
  generateTimeDistributionChart(filteredTasks);
  generateDailyProductivityChart(filteredTasks);

  // Show success notification
  showNotification(`Reports updated for ${getReadableTimeRange()}`, 'success');

  // 新增：渲染热力图
  renderHeatmap(filteredTasks);
}

// Get human-readable time range description
function getReadableTimeRange() {
  switch (activeRange) {
    case 'week': return 'This Week';
    case 'month': return 'This Month';
    case 'quarter': return 'Last 3 Months';
    case 'year': return 'This Year';
    case 'all': return 'All Time';
    default: return activeRange;
  }
}

// Generate summary statistics
function generateSummaryStats(filteredTasks) {
  // Count total tasks
  const totalTasks = filteredTasks.length;

  // Count completed tasks
  const completedTasks = filteredTasks.filter(task =>
    task.status && task.status.toLowerCase() === 'completed'
  ).length;

  // Calculate completion rate
  const completionRate = totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0;

  // Calculate total hours
  let totalSeconds = 0;
  filteredTasks.forEach(task => {
    totalSeconds += task.timeSpent || 0;
  });
  const totalHours = (totalSeconds / 3600).toFixed(1);

  // Calculate average daily hours
  const { startDate, endDate } = getDateRange();
  const daysDiff = Math.max(1, Math.ceil((endDate - startDate) / (1000 * 60 * 60 * 24)));
  const avgDailyHours = (totalSeconds / daysDiff / 3600).toFixed(1);

  // Update summary display
  document.getElementById('summary-total-tasks').textContent = totalTasks;
  document.getElementById('summary-completed-tasks').textContent = completedTasks;
  document.getElementById('summary-completion-rate').textContent = `${completionRate}%`;
  document.getElementById('summary-total-hours').textContent = `${totalHours}h`;
  document.getElementById('summary-avg-daily').textContent = `${avgDailyHours}h`;
}

// Generate status distribution
function generateStatusDistribution(filteredTasks) {
  // Get status counts
  const statusCounts = {};
  let maxCount = 0;

  filteredTasks.forEach(task => {
    const status = task.status || 'Undefined';
    statusCounts[status] = (statusCounts[status] || 0) + 1;
    maxCount = Math.max(maxCount, statusCounts[status]);
  });

  // Convert to array and sort by count (descending)
  const statusArray = Object.entries(statusCounts).map(([status, count]) => ({
    status,
    count,
    percentage: filteredTasks.length > 0
      ? Math.round((count / filteredTasks.length) * 100)
      : 0
  }));

  statusArray.sort((a, b) => b.count - a.count);

  // Generate table content
  const tbody = document.querySelector('#status-table tbody');
  tbody.innerHTML = '';

  if (statusArray.length === 0) {
    const emptyRow = document.createElement('tr');
    emptyRow.innerHTML = '<td colspan="4">No data available</td>';
    tbody.appendChild(emptyRow);
    return;
  }

  statusArray.forEach(item => {
    const row = document.createElement('tr');

    // Status name
    const statusCell = document.createElement('td');
    statusCell.textContent = item.status;

    // Count
    const countCell = document.createElement('td');
    countCell.textContent = item.count;

    // Percentage
    const percentageCell = document.createElement('td');
    percentageCell.textContent = `${item.percentage}%`;

    // Distribution bar
    const distributionCell = document.createElement('td');
    const progressBar = document.createElement('div');
    progressBar.className = 'progress-bar';

    const progressFill = document.createElement('div');
    progressFill.className = 'progress-fill';

    // Apply color based on status
    if (item.status.toLowerCase() === 'completed') {
      progressFill.classList.add('green');
    } else if (item.status.toLowerCase() === 'in progress') {
      progressFill.classList.add('blue');
    } else if (item.status.toLowerCase() === 'pending') {
      progressFill.classList.add('orange');
    }

    // Set width based on percentage of max count
    const width = maxCount > 0 ? (item.count / maxCount) * 100 : 0;
    progressFill.style.width = `${width}%`;

    progressBar.appendChild(progressFill);
    distributionCell.appendChild(progressBar);

    // Add cells to row
    row.appendChild(statusCell);
    row.appendChild(countCell);
    row.appendChild(percentageCell);
    row.appendChild(distributionCell);

    // Add row to table
    tbody.appendChild(row);
  });
}

// Generate tags analysis
function generateTagsAnalysis(filteredTasks) {
  // Get tag counts and hours
  const tagStats = {};
  let maxCount = 0;

  // Process all tasks with tags
  filteredTasks.forEach(task => {
    if (task.tags && Array.isArray(task.tags)) {
      task.tags.forEach(tag => {
        if (!tagStats[tag]) {
          tagStats[tag] = { count: 0, seconds: 0 };
        }
        tagStats[tag].count += 1;
        tagStats[tag].seconds += task.timeSpent || 0;
        maxCount = Math.max(maxCount, tagStats[tag].count);
      });
    }
  });

  // Convert to array and sort by count (descending)
  const tagsArray = Object.entries(tagStats).map(([tag, stats]) => ({
    tag,
    count: stats.count,
    hours: (stats.seconds / 3600).toFixed(1)
  }));

  tagsArray.sort((a, b) => b.count - a.count);

  // Generate table content
  const tbody = document.querySelector('#tags-table tbody');
  tbody.innerHTML = '';

  if (tagsArray.length === 0) {
    const emptyRow = document.createElement('tr');
    emptyRow.innerHTML = '<td colspan="4">No tags found</td>';
    tbody.appendChild(emptyRow);
    return;
  }

  // Limit to top 10 tags
  const topTags = tagsArray.slice(0, 10);

  topTags.forEach(item => {
    const row = document.createElement('tr');

    // Tag name
    const tagCell = document.createElement('td');
    tagCell.textContent = item.tag;

    // Count
    const countCell = document.createElement('td');
    countCell.textContent = item.count;

    // Hours
    const hoursCell = document.createElement('td');
    hoursCell.textContent = `${item.hours}h`;

    // Distribution bar
    const distributionCell = document.createElement('td');
    const progressBar = document.createElement('div');
    progressBar.className = 'progress-bar';

    const progressFill = document.createElement('div');
    progressFill.className = 'progress-fill';

    // Set width based on percentage of max count
    const width = maxCount > 0 ? (item.count / maxCount) * 100 : 0;
    progressFill.style.width = `${width}%`;

    progressBar.appendChild(progressFill);
    distributionCell.appendChild(progressBar);

    // Add cells to row
    row.appendChild(tagCell);
    row.appendChild(countCell);
    row.appendChild(hoursCell);
    row.appendChild(distributionCell);

    // Add row to table
    tbody.appendChild(row);
  });
}

// Format date for display
function formatDate(date) {
  if (!date || isNaN(date.getTime())) return 'Invalid date';

  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');

  return `${year}-${month}-${day}`;
}

// Format time from seconds
function formatTimeFromSeconds(seconds) {
  if (seconds >= 3600) {
    const hours = Math.floor(seconds / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);

    if (minutes > 0) {
      return `${hours}h ${minutes}min`;
    } else {
      return `${hours}h`;
    }
  } else {
    const minutes = Math.floor(seconds / 60);
    return `${minutes}min`;
  }
}

// Show notification
function showNotification(message, type = 'success') {
  const notification = document.getElementById('notification');
  const messageElement = document.getElementById('notification-message');

  notification.className = 'notification ' + type + ' show';
  messageElement.textContent = message;

  // Auto-hide after 3 seconds
  setTimeout(() => {
    notification.classList.remove('show');
  }, 3000);
}

// Generate completion trend chart
function generateCompletionTrendChart(filteredTasks) {
  const ctx = document.getElementById('completion-trend-chart').getContext('2d');

  // 设置画布高度
  ctx.canvas.style.height = '300px';

  // Prepare data for the last 7 days
  const dateLabels = [];
  const completedData = [];
  const createdData = [];

  // Get date range
  const { startDate, endDate } = getDateRange();
  const daysDiff = Math.min(14, Math.ceil((endDate - startDate) / (1000 * 60 * 60 * 24)));

  // Generate date labels and initialize counts
  for (let i = 0; i < daysDiff; i++) {
    const date = new Date(endDate);
    date.setDate(endDate.getDate() - i);

    // Format date as short day name + day
    const formatter = new Intl.DateTimeFormat('en-US', { weekday: 'short', day: 'numeric' });
    const dateLabel = formatter.format(date);

    dateLabels.unshift(dateLabel);
    completedData.unshift(0);
    createdData.unshift(0);
  }

  // Count tasks by date
  filteredTasks.forEach(task => {
    const taskDate = new Date(task.createdAt);
    taskDate.setHours(0, 0, 0, 0);

    // Calculate days ago
    const today = new Date(endDate);
    today.setHours(0, 0, 0, 0);
    const diffTime = today - taskDate;
    const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));

    // Count task created
    createdData[daysDiff - 1 - diffDays]++;

    // Count completed tasks
    if (task.status && task.status.toLowerCase() === 'completed') {
      // 总是优先使用completedAt日期
      if (task.completedAt) {
        const completedDate = new Date(task.completedAt);
        completedDate.setHours(0, 0, 0, 0);
        const completedDiffTime = today - completedDate;
        const completedDiffDays = Math.floor(completedDiffTime / (1000 * 60 * 60 * 24));

        if (completedDiffDays >= 0 && completedDiffDays < daysDiff) {
          completedData[daysDiff - 1 - completedDiffDays]++;
        }
      } else {
        // 只有在没有completedAt时才使用createdAt
        completedData[daysDiff - 1 - diffDays]++;
      }
    }
  });

  // Destroy existing chart if it exists
  if (window.completionChart) {
    window.completionChart.destroy();
  }

  // Create chart
  window.completionChart = new Chart(ctx, {
    type: 'line',
    data: {
      labels: dateLabels,
      datasets: [
        {
          label: 'Tasks Created',
          data: createdData,
          backgroundColor: 'rgba(54, 162, 235, 0.2)',
          borderColor: 'rgba(54, 162, 235, 1)',
          borderWidth: 2,
          tension: 0.3,
          pointRadius: 3,
          fill: true
        },
        {
          label: 'Tasks Completed',
          data: completedData,
          backgroundColor: 'rgba(75, 192, 192, 0.2)',
          borderColor: 'rgba(75, 192, 192, 1)',
          borderWidth: 2,
          tension: 0.3,
          pointRadius: 3,
          fill: true
        }
      ]
    },
    options: {
      responsive: true,
      maintainAspectRatio: false,
      plugins: {
        legend: {
          position: 'top',
        },
        title: {
          display: true,
          text: 'Task Completion Trend'
        }
      },
      scales: {
        y: {
          beginAtZero: true,
          ticks: {
            precision: 0
          }
        }
      }
    }
  });
}

// Generate time distribution chart
function generateTimeDistributionChart(filteredTasks) {
  const ctx = document.getElementById('time-distribution-chart').getContext('2d');

  // 设置画布高度
  ctx.canvas.style.height = '200px';

  // Prepare data for time distribution by tag
  const tagHours = {};
  let totalSeconds = 0;

  // Calculate time spent by tag
  filteredTasks.forEach(task => {
    const timeSpent = task.timeSpent || 0;
    totalSeconds += timeSpent;

    if (task.tags && task.tags.length > 0) {
      task.tags.forEach(tag => {
        tagHours[tag] = (tagHours[tag] || 0) + timeSpent;
      });
    } else {
      tagHours['No Tag'] = (tagHours['No Tag'] || 0) + timeSpent;
    }
  });

  // Convert to chart data format
  const labels = [];
  const data = [];
  const backgroundColors = [
    'rgba(255, 99, 132, 0.8)',
    'rgba(54, 162, 235, 0.8)',
    'rgba(255, 206, 86, 0.8)',
    'rgba(75, 192, 192, 0.8)',
    'rgba(153, 102, 255, 0.8)',
    'rgba(255, 159, 64, 0.8)',
    'rgba(199, 199, 199, 0.8)'
  ];

  // Sort tags by time spent
  const sortedTags = Object.entries(tagHours)
    .sort((a, b) => b[1] - a[1])
    .slice(0, 6); // Limit to top 6 tags

  // Add "Other" category for remaining tags
  let otherSeconds = 0;
  if (Object.keys(tagHours).length > 6) {
    Object.entries(tagHours)
      .sort((a, b) => b[1] - a[1])
      .slice(6)
      .forEach(([_, seconds]) => {
        otherSeconds += seconds;
      });
  }

  // Prepare chart data
  sortedTags.forEach(([tag, seconds], index) => {
    labels.push(tag);
    data.push((seconds / 3600).toFixed(1));
  });

  // Add "Other" category if needed
  if (otherSeconds > 0) {
    labels.push('Other');
    data.push((otherSeconds / 3600).toFixed(1));
  }

  // Destroy existing chart if it exists
  if (window.timeDistributionChart) {
    window.timeDistributionChart.destroy();
  }

  // Check if we have any data to display
  if (totalSeconds === 0) {
    ctx.font = '16px Arial';
    ctx.fillStyle = '#757575';
    ctx.textAlign = 'center';
    ctx.fillText('No time data available', ctx.canvas.width / 2, ctx.canvas.height / 2);
    return;
  }

  // Create chart
  window.timeDistributionChart = new Chart(ctx, {
    type: 'pie',
    data: {
      labels: labels,
      datasets: [{
        data: data,
        backgroundColor: backgroundColors.slice(0, labels.length),
        borderWidth: 1
      }]
    },
    options: {
      responsive: true,
      maintainAspectRatio: true,
      plugins: {
        legend: {
          position: 'right',
          labels: {
            boxWidth: 12,
            font: {
              size: 11
            }
          }
        },
        title: {
          display: true,
          text: 'Time Distribution by Tag'
        },
        tooltip: {
          callbacks: {
            label: function (context) {
              const label = context.label || '';
              const value = context.raw || 0;
              return `${label}: ${value} hours`;
            }
          }
        }
      }
    }
  });
}

// Generate daily productivity chart
function generateDailyProductivityChart(filteredTasks) {
  const ctx = document.getElementById('daily-productivity-chart').getContext('2d');

  // Get date range
  const { startDate, endDate } = getDateRange();
  const daysDiff = Math.min(7, Math.ceil((endDate - startDate) / (1000 * 60 * 60 * 24)));

  // Prepare data
  const labels = [];
  const hoursData = [];
  const taskCountData = [];

  // Generate date labels and initialize data
  for (let i = 0; i < daysDiff; i++) {
    const date = new Date(endDate);
    date.setDate(endDate.getDate() - i);

    // Format date as short day name
    const formatter = new Intl.DateTimeFormat('en-US', { weekday: 'short' });
    const dateLabel = formatter.format(date);

    labels.unshift(dateLabel);
    hoursData.unshift(0);
    taskCountData.unshift(0);
  }

  // Process tasks
  filteredTasks.forEach(task => {
    const taskDate = new Date(task.createdAt);
    taskDate.setHours(0, 0, 0, 0);

    // Calculate days ago
    const today = new Date(endDate);
    today.setHours(0, 0, 0, 0);
    const diffTime = today - taskDate;
    const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));

    if (diffDays >= 0 && diffDays < daysDiff) {
      // Add task count (only count each task once)
      taskCountData[daysDiff - 1 - diffDays]++;

      // Add hours spent (only if the task has recorded time)
      if (task.timeSpent && task.timeSpent > 0) {
        const hoursSpent = task.timeSpent / 3600;
        hoursData[daysDiff - 1 - diffDays] += hoursSpent;
      }
    }
  });

  // Round hours to 1 decimal place
  hoursData.forEach((hours, index) => {
    hoursData[index] = parseFloat(hours.toFixed(1));
  });

  // Calculate max values for y-axes with some padding
  const maxHours = Math.max(...hoursData, 1);
  const maxTasks = Math.max(...taskCountData, 1);

  // Destroy existing chart if it exists
  if (window.dailyProductivityChart) {
    window.dailyProductivityChart.destroy();
  }

  // Create chart
  window.dailyProductivityChart = new Chart(ctx, {
    type: 'bar',
    data: {
      labels: labels,
      datasets: [
        {
          label: 'Hours Worked',
          data: hoursData,
          backgroundColor: 'rgba(54, 162, 235, 0.8)',
          borderColor: 'rgba(54, 162, 235, 1)',
          borderWidth: 1,
          yAxisID: 'y'
        },
        {
          label: 'Task Count',
          data: taskCountData,
          type: 'line',
          backgroundColor: 'rgba(255, 99, 132, 0.2)',
          borderColor: 'rgba(255, 99, 132, 1)',
          borderWidth: 2,
          pointRadius: 3,
          yAxisID: 'y1'
        }
      ]
    },
    options: {
      responsive: true,
      maintainAspectRatio: true,
      plugins: {
        legend: {
          position: 'top',
        },
        title: {
          display: true,
          text: 'Daily Productivity'
        }
      },
      scales: {
        y: {
          type: 'linear',
          beginAtZero: true,
          position: 'left',
          min: 0,
          max: Math.ceil(maxHours * 1.2),
          title: {
            display: true,
            text: 'Hours'
          },
          ticks: {
            stepSize: Math.ceil(maxHours / 5),
            precision: 1
          }
        },
        y1: {
          type: 'linear',
          beginAtZero: true,
          position: 'right',
          min: 0,
          max: Math.ceil(maxTasks * 1.2),
          title: {
            display: true,
            text: 'Tasks'
          },
          ticks: {
            stepSize: Math.max(1, Math.ceil(maxTasks / 5)),
            precision: 0
          },
          grid: {
            drawOnChartArea: false
          }
        }
      }
    }
  });

  // 强制设置画布高度
  setTimeout(() => {
    ctx.canvas.style.height = '200px';
    ctx.canvas.height = 200;
  }, 0);
}

// ===== 热力图依赖（如未引入可在 HTML 里补充） =====
// 依赖已在 HTML 引入：chart.js、chartjs-chart-matrix.js、chartjs-adapter-date-fns.js

// ===== 复制自 heatmap.js =====
function generateYearDataFromTasks(tasks) {
  const weekLabels = ['Mo','Tu','We','Th','Fr','Sa','Su'];
  const year = new Date().getFullYear();
  const start = new Date(year, 0, 1);
  const end = new Date(year, 11, 31);
  const dayMap = {};
  for (const task of tasks) {
    const time = (typeof task.timeSpent === 'number' && task.timeSpent > 0)
      ? task.timeSpent / 3600
      : (typeof task.time === 'number' ? task.time : 0);
    if (!time) continue;
    const startDate = task.createdAt ? new Date(task.createdAt.slice(0,10)) : null;
    const endDate = task.completedAt ? new Date(task.completedAt.slice(0,10)) : startDate;
    if (!startDate || !endDate) continue;
    const days = Math.max(1, Math.round((endDate - startDate) / 86400000) + 1);
    const avgTime = time / days;
    let dt = new Date(startDate);
    while (dt <= endDate) {
      const iso = dt.toISOString().slice(0,10);
      dayMap[iso] = (dayMap[iso] || 0) + avgTime;
      dt.setDate(dt.getDate() + 1);
    }
  }
  const data = [];
  let dt = new Date(start);
  while (dt <= end) {
    const iso = dt.toISOString().slice(0, 10);
    const weekday = dt.getDay() === 0 ? 6 : dt.getDay() - 1;
    data.push({
      x: iso,
      y: weekLabels[weekday],
      d: iso,
      v: +(dayMap[iso] || 0)
    });
    dt.setDate(dt.getDate() + 1);
  }
  return data;
}

function renderHeatmap(tasks) {
  const data = {
    datasets: [{
      label: 'Work Hours',
      data: generateYearDataFromTasks(tasks),
      backgroundColor(c) {
        const value = c.dataset.data[c.dataIndex].v;
        if (value === 0) return '#ebedf0';
        if (value > 8) return '#216e39';
        if (value > 6) return '#30a14e';
        if (value > 4) return '#40c463';
        if (value > 0) return '#9be9a8';
        return '#ebedf0';
      },
      borderWidth: 0,
      width(ctx) {
        const a = ctx.chart.chartArea || {};
        return Math.min((a.right - a.left) / 53 - 2, (a.bottom - a.top) / 7 - 2, 14);
      },
      height(ctx) {
        const a = ctx.chart.chartArea || {};
        return Math.min((a.bottom - a.top) / 7 - 2, (a.right - a.left) / 53 - 2, 14);
      }
    }]
  };
  const options = {
    aspectRatio: 5,
    maintainAspectRatio: false,
    plugins: {
      legend: false,
      tooltip: {
        displayColors: false,
        callbacks: {
          title(context) { return context[0].raw.d; },
          label(context) {
            const v = context.raw;
            return [`Hours: ${v.v.toFixed(2)}`];
          }
        }
      },
    },
    scales: {
      x: {
        type: 'time',
        position: 'top',
        time: {
          unit: 'week',
          round: 'week',
          displayFormats: { week: 'MMM dd' }
        },
        offset: true,
        grid: { display: false },
        ticks: { maxRotation: 0, autoSkip: true, font: { size: 10 } }
      },
      y: {
        type: 'category',
        labels: ['Mo','Tu','We','Th','Fr','Sa','Su'],
        offset: true,
        grid: { display: false },
        reverse: false
      }
    },
    animation: false
  };
  const canvas = document.getElementById('reports-heatmap-canvas');
  if (!canvas) return;
  const ctx = canvas.getContext('2d');
  if (window.reportsHeatmapChart) {
    window.reportsHeatmapChart.destroy();
  }
  window.reportsHeatmapChart = new Chart(ctx, { type: 'matrix', data, options });
} 